#include <iostream>
#include <thread>
#include <chrono>
#include <exception>
#include  <map>

class thread_interrupt
{
};

std::map<std::thread::id, bool> g_id_interflag_maps;

static void interrupt_point()
{
    auto m_id = std::this_thread::get_id();
    // std::cout << "will throw interrrupt, tpid is " << m_id << ", m_inter_flag is " << (g_id_interflag_maps[m_id] ? "true" : "false") << std::endl;
    if (g_id_interflag_maps[m_id])
    {
        g_id_interflag_maps[m_id] = false;
        throw thread_interrupt();
        // std::cout << "throw interrrupt after" << std::endl;
    }
}
static void interrupt(const std::thread &t)
{
    // std::cout << "interrupted after, tpid is " << t.get_id() << std::endl;
    g_id_interflag_maps[t.get_id()] = true;
    // std::cout << "interrupted after, m_inter_flag is " << (g_id_interflag_maps[t.get_id()] ? "true" : "false") << std::endl;
}

  int
  main()
  try
  {
    // std::cout  << "main thread tpid is " << std::this_thread::get_id() << std::endl;
    std::thread t([](){
        try {
            long long i = 0;
            while (i < 10) {
                std::this_thread::sleep_for(std::chrono::milliseconds(1000));
                std::cout << "haha " << i++ << ", tpid is " << std::this_thread::get_id() << std::endl;
                interrupt_point();
            } 
        } catch(thread_interrupt) {
            std::cout << "caught error" << std::endl;
        }
    });

    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    interrupt(t);

    t.join();
  }catch(const std::exception& e) {
    std::cout << e.what() << std::endl;
  }